package server;

import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URLDecoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import java.util.List;
import java.util.concurrent.Executors;

public class httpserver implements HttpHandler {
	final static int HTTPPORT=8080;
	private Map<String, Object> parameters;
	public static Positioning myPositioning;
	
    /**
	*Server is waiting for a query
	*/
	public void handle(HttpExchange exchange) throws IOException {
	    parameters = new HashMap<String, Object>();
	    //get the requested method 
		String requestMethod = exchange.getRequestMethod();
		//if the requested method is GET
		if (requestMethod.equalsIgnoreCase("GET")) {
			String packet=null;
			//readout the received parameters 
			parseGetParameters(exchange);
			if(parameters.get("command").equals("getXY"))
			{
				System.out.println("Positionsanforderung");
				ReferencePoint spotPosition=myPositioning.getLastSpotPosition();
				//put the response into "parameters"
				parameters.put("X", spotPosition.X);
				parameters.put("Y", spotPosition.Y);

				parameters.put("SpotId", myPositioning.getSpotToLocate());
				parameters.put("PosId", spotPosition.id);	
			}
			if(parameters.get("command").equals("getReferencePoints"))
			{
				//put all reference points into "parameters"
				for(int i=0;i<myPositioning.myRefPoints.size();i++)
				{	
					parameters.put("X"+i,myPositioning.myRefPoints.get(i).X);
					parameters.put("Y"+i,myPositioning.myRefPoints.get(i).Y);
				}
			}
			if(parameters.get("command").equals("AddSampleToReferencePoint"))
			{
				//get the received parameters
				int x=Integer.parseInt(parameters.get("X").toString());
				int y=Integer.parseInt(parameters.get("Y").toString());
				int sampleCount=Integer.parseInt(parameters.get("sampleCount").toString());
				boolean keepTable=Boolean.parseBoolean(parameters.get("keepTable").toString());
				myPositioning.addSampleToRefPoint(x,y,sampleCount,keepTable);
				System.out.println("X="+x);
				System.out.println("Y="+y);
				System.out.println("sampleCount="+sampleCount);
				System.out.println("keepTable="+keepTable);
			}
			if(parameters.get("command").equals("AddReferencePoint"))
			{
				//get the received parameters
				int x=Integer.parseInt(parameters.get("X").toString());
				int y=Integer.parseInt(parameters.get("Y").toString());
				System.out.println("AddReferencePoint x="+x+" y="+y);
				int sampleCount=Integer.parseInt(parameters.get("sampleCount").toString());
				myPositioning.addRefPoint(x,y,sampleCount);
				System.out.println("X="+x);
				System.out.println("Y="+y);
				System.out.println("sampleCount="+sampleCount);
			}
			if(parameters.get("command").equals("isRefPointSamplingFinished"))
			{
				//put the response into "parameters"
				if(myPositioning.getSamplesToGo()==0)					
					parameters.put("RefPointSamplingFinished",true);
				else
					parameters.put("RefPointSamplingFinished",false);
			}
			
			if(parameters.get("command").equals("sendCorrectedXYCoordinates"))
			{	
				//get the received parameters
				int x=0;
				int y=0;
				x=Integer.parseInt(parameters.get("X").toString());
				y=Integer.parseInt(parameters.get("Y").toString());
				System.out.println("CorrectedXYCoordinates:");
				System.out.println("X="+x);
				System.out.println("Y="+y);
				
			}
			if(parameters.get("command").equals("StopPositioning"))
			{
				myPositioning.stopPositioning();	
			}
			if(parameters.get("command").equals("ClearAllRefPoints"))
			{
				myPositioning.removeAllRefPoints();
			}
			if(parameters.get("command").equals("RemoveRefPoint"))
			{
				//get the received parameters
				int x=Integer.parseInt(parameters.get("X").toString());
				int y=Integer.parseInt(parameters.get("Y").toString());
				myPositioning.removeRefPoint(x, y);
			}
			if(parameters.get("command").equals("sendpacket"))
			{
				//receives the packet from the SunSpot 
				packet=(String)parameters.get("packet");
				System.out.println("Packet="+packet);
				//put the received packet into the dataset
				ArrayList<DataSet> dataset = new ArrayList<DataSet>();
				dataset=parseGetPacket(packet);
				myPositioning.addSamples(dataset); 
				parameters.clear();
				parameters.put("command","sendpacket");
			}
			String response= parameters.toString();
			//return the response to the client
			exchange.sendResponseHeaders(200, response.length());
			OutputStream os = exchange.getResponseBody();
			os.write(response.getBytes());
			os.close();      			
		}
	}

    private void parseGetParameters(HttpExchange exchange)throws UnsupportedEncodingException {
	    //the received data are examined and stored in parameter
    	URI requestedUri = exchange.getRequestURI();
	    String query = requestedUri.getRawQuery();
	    parseQuery(query, parameters);
	    exchange.setAttribute("parameters", parameters);
	}

    private void parseQuery(String query, Map<String, Object> parameters)throws UnsupportedEncodingException {
    if (query != null) {
    	
        String pairs[] = query.split("[&]");
        for (String pair : pairs) {
            String param[] = pair.split("[=]");

            String key = null;
            String value = null;
            if (param.length > 0) {
                key = URLDecoder.decode(param[0],
                    System.getProperty("file.encoding"));
            }

            if (param.length > 1) {
                value = URLDecoder.decode(param[1],
                    System.getProperty("file.encoding"));
            }

            if (parameters.containsKey(key)) {
                Object obj = parameters.get(key);
                if(obj instanceof List<?>) {
                    List<String> values = (List<String>)obj;
                    values.add(value);
                } else if(obj instanceof String) {
                    List<String> values = new ArrayList<String>();
                    values.add((String)obj);
                    values.add(value);
                    parameters.put(key, values);
                }
            } else {
                parameters.put(key, value);
            }
        }
    }
}
	
    public ArrayList<DataSet> parseGetPacket(String packets){ //TODO change to private
        ArrayList<DataSet> dataset = new ArrayList<DataSet>();
        //the end of a packet is marked with a *
        StringTokenizer tokenizerPacket = new StringTokenizer(packets.substring(0, packets.length()), "*");
        while(tokenizerPacket.hasMoreTokens()){
        	String packetData =tokenizerPacket.nextToken();
        	//each packet contains several datasets and the received time after the #
	        StringTokenizer tokenizer = new StringTokenizer(packetData.substring(0, packetData.indexOf("#")), ";");
	        String temp = null;
	        //the received time is separated
	        String receivedTime = packetData.substring(packetData.indexOf("#") + 1, packetData.length());
	        while (tokenizer.hasMoreTokens()) {
	        	//the dataset is separated
	        	DataSet set=new DataSet();
	            temp = tokenizer.nextToken();
	            set.setSpotId(temp.substring(0, temp.indexOf("%")));
	            if(set.getSpotId().charAt(0)=='P'){
	            	set.setSpotId(set.getSpotId().substring(1));
	            	set.setNewpacket(true);
	            }
	            set.setSeqNr(Integer.parseInt(temp.substring(temp.indexOf("%") + 1, temp.indexOf('|'))));
	            set.setRssi(Integer.parseInt(temp.substring(temp.indexOf("|") + 1, temp.indexOf('$'))));
	            set.setLQI(Integer.parseInt(temp.substring(temp.indexOf("$") + 1, temp.length())));
	            set.setTime(receivedTime);
	            SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
	            Date d = new Date();
	            set.setSendingTime(s.format(d).toString());
	            dataset.add(set);
	        } 
        }	
        return (dataset);
    }
    /**
    *Initiate the server and opens the port were the server is listening
	*/
	private static void initHTTPConnection() {
		InetSocketAddress addr = new InetSocketAddress(HTTPPORT);
		HttpServer server;
		try {
			server = HttpServer.create(addr, 0);
			server.createContext("/", new httpserver());
			server.setExecutor(Executors.newCachedThreadPool());
			server.start();
		} catch (IOException e) {
			System.out.println("HTTPException");
			e.printStackTrace();
		}
		System.out.println("Server is listening on port "+HTTPPORT);
	}
	
	
	
	
	
	public static void main(String[] args)  {
		
		Positioning positioning=new Positioning();
		
				
		httpserver server=new httpserver();
				
		server.myPositioning=positioning;
		
		//server.myPositioning.determinePosition(server.myPositioning.refPointSamples.get(9));

		
		initHTTPConnection();
		
		/*
		DataSet [] erg=server.algorithm(server.refPointsMeanValues.get(0),"LQI",2);		
		for(int i=0;i<erg.length;i++){
			System.out.println(erg[i].getPosID());
		}
		*/
	
	}
}
